﻿using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;

namespace PackTool
{
    // 版本检测结束
    public class CheckVersion
    {
        string LocalConfigPath;
        string LocalPath;

        public delegate void CheckVersionEnd();

        CheckVersionEnd mCheckVersionEnd;

        public delegate void UpdateInfo(string text);
        UpdateInfo mUpdateInfo;

        // Use this for initialization
        public void Start(CheckVersionEnd f, UpdateInfo info)
        {
            mCheckVersionEnd = f;
            mUpdateInfo = info;

#if UNITY_EDITOR
            LocalConfigPath = "file://" + ResourcesPath.LocalConfigPath;
            LocalPath = "file://" + ResourcesPath.LocalPath;
#endif
#if (UNITY_ANDROID || UNITY_IPHONE) && (!UNITY_EDITOR)
            LocalConfigPath = ResourcesPath.LocalConfigPath;
            LocalPath = ResourcesPath.LocalPath;
#endif
            mUpdateInfo("下载本地版本文件!");

            // 加载下本地的版本文件
            ResourceDown.Instance.Load(LocalConfigPath + "version.txt", loadLocalVersionEnd);
        }

        // 服务器的文件数据
        Dictionary<string, byte[]> ServerFileData = new Dictionary<string, byte[]>();

        System.Version version; // 版本号
        void loadLocalVersionEnd(WWW www, object p)
        {
            if (www.error != null)
            {
                // 有错误，可能本地没有版本文件，需要更新所有的资源
                version = null;
                mUpdateInfo("本地版本文件下载失败，需要更新所有资源!");
            }
            else
            {
                version = new System.Version(www.text);
                mUpdateInfo("本地版本:" + version);
            }

            Debug.Log(string.Format("version:{0} file:{1}", version, www.url));

            mUpdateInfo("下载服务器版本文件！");

            // 去服务器更新下新的版本
            ResourceDown.Instance.Load(ResourcesPath.RemoteConfigPath + "version.txt", loadServerVersionEnd);
        }

        void loadServerVersionEnd(WWW www, object p)
        {
            if (www.error != null)
            {
                Debug.Log(string.Format("服务器版本下载错误!{0} url:{1}", www.error, www.url));
                mUpdateInfo("服务器版本下载错误！");
                if (mCheckVersionEnd != null)
                    mCheckVersionEnd();
                return; // 服务器版本错误
            }

            System.Version serverVersion = new System.Version(www.text);
            mUpdateInfo("服务器版本:" + serverVersion);
            if (serverVersion == version)
            {
                // 版本一至，那么，不需要更新
                Debug.Log("版本一至不需要更新!");
                mUpdateInfo("版本一至不需要更新!");

                if (mCheckVersionEnd != null)
                    mCheckVersionEnd();
            }
            else
            {
                Debug.Log(string.Format("server version:{0} file:{1}", serverVersion, www.url));

                ServerFileData[LocalConfigPath + "version.txt"] = www.bytes;

                // 版本不一至，需要更新至最新版本
                // 加载下本地的md5文件列表
                mUpdateInfo("版本不一至，下载本地的md5文件列表!");
                ResourceDown.Instance.Load("file://" + LocalConfigPath + "FilesMD5.csv", LoadLocalMd5FileEnd);
            }
        }

        Dictionary<string, string> MD5FileList = new Dictionary<string, string>();
        void LoadLocalMd5FileEnd(WWW www, object p)
        {
            if (www.error != null)
            {
                // 没有找到本地文件，那么
                Debug.Log(string.Format("没有查找到本地的MD5文件!{0}! url:{1}", www.error, www.url));
                mUpdateInfo("没有查找到本地的MD5文件!");
            }
            else
            {
                Debug.Log(string.Format("加载本地MD5文件成功!url:{0}", www.url));
                mUpdateInfo("加载本地MD5文件成功!");

                // 找着了本地文件
                Csv.CsvReader csv = new Csv.CsvReader();
                string text = www.text;
                csv.Load(ref text, ',');
                for (int i = 0; i < csv.getYCount(); ++i)
                    MD5FileList.Add(csv.getStr(i, 0).Replace('\\', '/'), csv.getStr(i, 1));
            }

            // 再去下载下服务器的md5文件列表
            mUpdateInfo("加载服务器MD5文件!");
            ResourceDown.Instance.Load(ResourcesPath.RemoteConfigPath + "FilesMD5.csv", LoadServerMd5FileEnd);
        }

        ThreadFileSave mThreadFileSave;
        List<string[]> UpdateFileList = new List<string[]>(); // 等更新的文件列表
        void LoadServerMd5FileEnd(WWW www, object p)
        {
            if (www.error != null)
            {
                // 没有找到服务器的md5文件，那么
                Debug.Log(string.Format("没有查找到服务器的MD5文件!{0}", www.error));
                mUpdateInfo("加载服务器MD5文件失败!");

                if (mCheckVersionEnd != null)
                    mCheckVersionEnd();
            }
            else
            {
                Debug.Log(string.Format("加载服务器MD5文件成功!url:{0}", www.url));
                mUpdateInfo("加载服务器MD5文件成功!");

                //ServerFileData[LocalConfigPath + "FilesMD5.csv"] = www.bytes;

                Dictionary<string, string> ServerMd5List = new Dictionary<string, string>();
                Csv.CsvReader csv = new Csv.CsvReader();
                string text = www.text;
                csv.Load(ref text, ',');
                string file;
                for (int i = 0; i < csv.getYCount(); ++i)
                {
                    if (!string.IsNullOrEmpty((file = csv.getStr(i, 0).Replace('\\', '/'))))
                    {
                        if (!ServerMd5List.ContainsKey(file))
                        {
                            ServerMd5List.Add(file, csv.getStr(i, 1));
                        }
                        else
                            Debug.LogError(string.Format("file:{0} rep!", file));
                    }
                }

                // 开始资源的更新,先删除用无的文件
                string delfile;
                foreach (KeyValuePair<string, string> itor in MD5FileList)
                {
                    if (!ServerMd5List.ContainsKey(itor.Key))
                    {
                        // 可以删除本地的文件
                        delfile = LocalPath + itor.Key;
                        if (File.Exists(delfile))
                        {
                            File.Delete(delfile);
                        }
                    }
                }

                // 一样的文件
                Dictionary<string, string> SameFileList = new Dictionary<string, string>();

                // 下载需要更新的资源                
                string md5 = "";
                foreach (KeyValuePair<string, string> itor in ServerMd5List)
                {
                    if ((!MD5FileList.TryGetValue(itor.Key, out md5)) || itor.Value != md5)
                    {
                        UpdateFileList.Add(new string[2] { itor.Key, itor.Value });
                    }
                    else
                    {
                        SameFileList.Add(itor.Key, itor.Value);
                    }
                }

                // 开始向服务器请求资源下载
                if (UpdateFileList.Count == 0)
                {
                    WriteFileToLocal();
                }
                else
                {
                    mThreadFileSave = new ThreadFileSave();
                    mThreadFileSave.init(SameFileList, ResourcesPath.LocalConfigPath + "FilesMD5.csv");

                    current = 0;
                    Debug.Log(string.Format("下中{0}:{1}", current, UpdateFileList[0][0]));
                    ResourceDown.Instance.Load(ResourcesPath.RemotePath + UpdateFileList[0][0], LoadServerFileEnd);
                }
            }
        }

        void LoadServerFileEnd(WWW www, object p)
        {
            current++;
            if (www.error != null)
            {
                Debug.LogError(string.Format("下载服务器资源失败!路径:{0} error:{1}", www.url, www.error));
            }
            else
            {
                string[] files = UpdateFileList[current - 1];
                //ServerFileData.Add(LocalPath + files[0], www.bytes);
                mThreadFileSave.SaveFile(LocalPath + files[0], www.bytes, files[0], files[1]);
                Debug.Log(string.Format("下载服务器资源成功!路径:{0}", www.url));
            }

            if (current == UpdateFileList.Count)
            {
                Debug.Log("资源下载完成!");
                WriteFileToLocal();
            }
            else
            {
                Debug.Log(string.Format("下中{0}:{1}", current, UpdateFileList[current][0]));
                ResourceDown.Instance.Load(ResourcesPath.RemotePath + UpdateFileList[current][0], LoadServerFileEnd);
            }
        }

        int current = 0;

        public void Release()
        {
            if (mThreadFileSave != null)
            {
                mThreadFileSave.Release();
                mThreadFileSave = null;
            }
        }

        // 定入文件到本地
        void WriteFileToLocal()
        {
            foreach (KeyValuePair<string, byte[]> itor in ServerFileData)
            {
                string dir = itor.Key.Substring(0, Mathf.Max(itor.Key.LastIndexOf('/'), itor.Key.LastIndexOf('\\')));
                if (dir.LastIndexOf("file://") == 0)
                {
                    dir = dir.Substring(7);
                    Directory.CreateDirectory(dir);
                    dir = itor.Key.Substring(7);
                }
                else
                {
                    Directory.CreateDirectory(dir);
                    dir = itor.Key;
                }

                FileStream fileStream = new FileStream(dir, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
                fileStream.Write(itor.Value, 0, itor.Value.Length);
                fileStream.Flush();
                fileStream.Close();

                Debug.Log(string.Format("更新资源:{0}", itor.Key));
            }

            if (mThreadFileSave != null)
            {
                mThreadFileSave.Release();
                mThreadFileSave = null;
            }

            if (mCheckVersionEnd != null)
                mCheckVersionEnd();
        }
    }
}